/**
 * Copyright 2005 The Apache Software Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.edi.db.connection;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.edi.db.cfg.Environment;
import com.edi.util.PropertiesHelper;
import com.edi.util.ReflectHelper;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import com.mchange.v2.c3p0.DataSources;

/**
 * A connection provider that uses a C3P0 connection pool. Hibernate will use
 * this by default if the <tt>hibernate.c3p0.*</tt> properties are set.
 * 
 * @see ConnectionProvider
 * @author various people
 */
public class C3P0ConnectionProvider implements ConnectionProvider {

	//	private DataSource ds;
	private ComboPooledDataSource ds;
	private Integer isolation;
	private boolean autocommit;
	private String jdbcUrl;

	private static final Log log = LogFactory.getLog(C3P0ConnectionProvider.class);

	public Connection getConnection() throws SQLException {
		//log.debug("// Enter getConnection()");
		// ds = class com.mchange.v2.c3p0.PoolBackedDataSource 
		//log.debug("// ds = "+ds.getClass().toString());
		//		log.debug("c3p0 : "+ds.getUser());
		//		log.debug("c3p0 : "+ds.getPassword());
		//		log.debug("c3p0 : "+ds.getDriverClass());
		final Connection c = ds.getConnection();
		//log.debug("// getConnection from DateSource");
		if (isolation != null)
			c.setTransactionIsolation(isolation.intValue());
		if (c.getAutoCommit() != autocommit)
			c.setAutoCommit(autocommit);
		//log.debug("// return getConnection from DateSource");
		return c;
	}

	public void closeConnection(Connection conn) throws SQLException {
		//log.debug("// Enter closeConnection");
		// conn = class com.mchange.v2.c3p0.impl.NewProxyConnection
		//log.debug("// conn = "+conn.getClass());
		conn.close();
	}

	public void configure(Properties props) throws Exception {
		//log.debug("// Configure C3P0ConnectionProvider : ");
		String jdbcDriverClass = props.getProperty(Environment.DRIVER);
		if (jdbcDriverClass == null)
			jdbcDriverClass = PropertiesHelper.getDbDriver(props
					.getProperty(Environment.DIALECT));

		jdbcUrl = props.getProperty(Environment.URL);
		if (jdbcUrl == null)
			jdbcUrl = PropertiesHelper.getDbUrl(props
					.getProperty(Environment.SERVER), props
					.getProperty(Environment.DBNAME), props
					.getProperty(Environment.USERNAME), props
					.getProperty(Environment.PASSWD), props
					.getProperty(Environment.DIALECT));
		if (jdbcUrl == null)
			throw new Exception("jdbcUrl 为空！");
		Properties connectionProps = ConnectionProviderFactory
				.getConnectionProperties(props);

		log.info("C3P0 using driver: " + jdbcDriverClass + " at URL: "
				+ jdbcUrl);
		log.info("Connection properties: "
				+ PropertiesHelper.maskOut(connectionProps, "password"));

		autocommit = false;
		log.info("autocommit mode: " + autocommit);

		if (jdbcDriverClass == null) {
			throw new ClassNotFoundException("jdbc驱动未能指定");
		} else {
			try {
				Class.forName(jdbcDriverClass);
			} catch (ClassNotFoundException cnfe) {
				try {
					ReflectHelper.classForName(jdbcDriverClass);
				} catch (ClassNotFoundException e) {
					String msg = "JDBC Driver class not found: "
							+ jdbcDriverClass;
					log.fatal(msg, e);
					throw new Exception(msg, e);
				}
			}
		}

		try {

			int minPoolSize = PropertiesHelper.getInt(
					Environment.MINCONNECTIONS, props, 1);
			int maxPoolSize = PropertiesHelper.getInt(
					Environment.MAXCONNECTIONS, props, 100);
			int maxIdleTime = PropertiesHelper.getInt(
					Environment.CONNECTIONTIMEOUT, props, 0);
			String user = props.getProperty(Environment.USERNAME);
			String password = props.getProperty(Environment.PASSWD);
			int maxStatements = 0;
			int acquireIncrement = 1;
			int idleTestPeriod = 0;

			log.debug("// minPoolSize = " + minPoolSize);
			log.debug("// maxPoolSize = " + maxPoolSize);
			log.debug("// maxIdleTime = " + maxIdleTime);
			log.debug("// maxStatements = " + maxStatements);
			log.debug("// acquireIncrement = " + acquireIncrement);
			log.debug("// idleTestPeriod = " + idleTestPeriod);

			//			PoolConfig pcfg = new PoolConfig();
			//			pcfg.setInitialPoolSize(minPoolSize);
			//			pcfg.setMinPoolSize(minPoolSize);
			//			pcfg.setMaxPoolSize(maxPoolSize);
			//			pcfg.setAcquireIncrement(acquireIncrement);
			//			pcfg.setMaxIdleTime(maxIdleTime);
			//			pcfg.setMaxStatements(maxStatements);
			//			pcfg.setIdleConnectionTestPeriod(idleTestPeriod);

			/*
			 * DataSource unpooled = DataSources.unpooledDataSource( jdbcUrl,
			 * props.getProperty(Environment.USER),
			 * props.getProperty(Environment.PASS) );
			 */
			//			DataSource unpooled = DataSources.unpooledDataSource(jdbcUrl, connectionProps);
			//			ds = DataSources.pooledDataSource(unpooled, pcfg);
			ds = new ComboPooledDataSource();
			ds.setDriverClass(jdbcDriverClass);
			ds.setJdbcUrl(jdbcUrl);
			ds.setUser(user);
			ds.setPassword(password);
			ds.setInitialPoolSize(minPoolSize);
			ds.setMinPoolSize(minPoolSize);
			ds.setMaxPoolSize(maxPoolSize);
			ds.setAcquireIncrement(acquireIncrement);
			ds.setMaxIdleTime(maxIdleTime);
			ds.setMaxStatements(maxStatements);
			ds.setIdleConnectionTestPeriod(idleTestPeriod);

		} catch (Exception e) {
			log.fatal("could not instantiate C3P0 connection pool", e);
			throw new Exception("Could not instantiate C3P0 connection pool", e);
		}

		//		log.debug("// Environment.ISOLATION = "+Environment.ISOLATION);
		//		String i = props.getProperty(Environment.ISOLATION);
		//		log.debug("// i = "+i);
		//		if (i==null) {
		//			isolation=null;
		//		}
		//		else {
		//			isolation = new Integer(i);
		//		}

	}

	public String getUrl() {
		return this.jdbcUrl;
	}

	public void close() {
		try {
			DataSources.destroy(ds);
		} catch (SQLException sqle) {
			log.warn("could not destroy C3P0 connection pool", sqle);
		}
	}

	public boolean supportsAggressiveRelease() {
		return true;
	}

}
